﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace XFFSM
{
    public class FSMController : MonoBehaviour
    {

        #region 字段

        public RuntimeFSMController runtimeFSMController;
        
        private RuntimeFSMController _runtimeFSMController;

        // 所有的参数
        internal Dictionary<string, FSMParameterData> parameters = new Dictionary<string, FSMParameterData>();

        // 所有的状态
        internal Dictionary<string, FSMStateNode> states = new Dictionary<string, FSMStateNode>();

        internal List<FSMTransition> transitions = new List<FSMTransition>();

        // 缓存组件
        private Dictionary<string, Dictionary<Type, UnityEngine.Object>> components = new Dictionary<string, Dictionary<Type, UnityEngine.Object>>();

        #endregion

        #region 属性

        public RuntimeFSMController RuntimeFSMController {
            get {
                if (Application.isPlaying) {
                    return _runtimeFSMController;
                }
                return runtimeFSMController;
            }
        }

        internal static IExecuteState executeState { get; private set; } = new DefualtExecuteState();


        // 默认状态
        internal FSMStateNode defaultState { get; private set; } = null;

        // 当前正在执行的状态
        public FSMStateNode currentState { get; private set; } = null;

        // 当前的过渡
        public FSMTransition currentTransition { get; private set; } = null;

        #endregion

        #region 生命周期

        private void Start()
        {
            Init();
        }

        private void Update()
        {
            if (currentState != null) currentState.OnUpdate(); 
        }

        private void LateUpdate()
        {
            if (currentState != null) currentState.OnLateUpdate();
        }

        private void FixedUpdate()
        {
            if (currentState != null) currentState.OnFixedUpdate();
        }


        #endregion

        #region 方法

        // 初始化
        private void Init() {

            // 把数据复制一份
            if (runtimeFSMController == null) return;
            _runtimeFSMController = GameObject.Instantiate(runtimeFSMController);

            // 参数
            for (int i = 0; i < _runtimeFSMController.parameters.Count; i++)
            {

                if (parameters.ContainsKey(_runtimeFSMController.parameters[i].name)) {
                    Debug.LogErrorFormat("参数名称重复:{0}",_runtimeFSMController.parameters[i].name);
                    continue;
                }
                _runtimeFSMController.parameters[i].onValueChange = null;
                parameters.Add(_runtimeFSMController.parameters[i].name, _runtimeFSMController.parameters[i]);
            }

            // 状态
            for (int i = 0; i < _runtimeFSMController.states.Count; i++)
            {
                FSMStateNodeData stateData = _runtimeFSMController.states[i];
                FSMStateNode state = new FSMStateNode(stateData, this);

                if ( states.ContainsKey(stateData.name) ) 
                {
                    Debug.LogErrorFormat("状态名称重复:{0}",stateData.name);
                    continue;
                }

                if (stateData.defaultState) {
                    defaultState = state;
                }

                states.Add(stateData.name, state);
            }
            // 过渡

            foreach (var item in _runtimeFSMController.transitions)
            {
                FSMTransition transition = new FSMTransition(this, item);
                transitions.Add(transition);
            }

            // 找到默认状态 切换
            SwitchState(defaultState,null);

            // 检测一下 已满足的过渡 判断是否需要切换状态
            foreach (var item in transitions)
            {
                item.CheckConditionIsMeet();
            }

        }

        public void SetBool(string name,bool v) {
            SetParamter(name, v ? 1 : 0, ParameterType.Bool);
        }

        public void SetFloat(string name,float v) {
            SetParamter(name, v , ParameterType.Float);
        }

        public void SetInt(string name,int v) {
            SetParamter(name, v, ParameterType.Int);
        }

        private void SetParamter(string name,float v,ParameterType type) {
            FSMParameterData parameter;
            if (parameters.TryGetValue(name, out parameter))
            {
                if (parameter.parameterType == type)
                {
                    parameter.Value = v;
                }
                else
                {
                    Debug.LogFormat("修改参数失败:{0},类型错误:{1}", name, parameter.parameterType);
                }
            }
            else
            {
                Debug.LogFormat("未查询到参数:{0}", name);
            }
        }

        public static void SetIExecuteState(IExecuteState execute) {
            if (execute!=null) {
                executeState = execute;
            }
        }

        internal void SwitchState(FSMStateNode state,FSMTransition transition) {

            if (state == null) return;

            if (currentState!=null) 
                currentState.OnExit();

            currentState = state;

            state.OnEnter();

            currentTransition = transition;

        }

        public T GetComponent<T>(string path = "") where T : UnityEngine.Object {
            return GetComponent(typeof(T),path) as T;
        }

        public UnityEngine.Object GetComponent(Type type, string path = "") {

            if ( !components.ContainsKey(path) ) {
                components.Add(path, new Dictionary<Type, UnityEngine.Object>());
            }

            if (components.ContainsKey(path) && components[path].ContainsKey(type)) {
                return components[path][type];
            }

            UnityEngine.Object component = null;

            if (string.IsNullOrEmpty(path))
            {
                component = transform.GetComponent(type);
            }
            else {
                Transform child = transform.Find(path);

                if (child != null)
                {
                    component = child.GetComponent(type);
                }
                else {
                    Debug.LogErrorFormat("未查询到子节点:{0}",path);
                }

            }

            if (component != null) {
                components[path].Add(type, component);
            }

            return component;
        }

        #endregion


    }

}

